今天來講 Macrotask vs Microtask 大家可能常搞錯的部分
這邊我先簡單介紹一下 Event Loop,並在文章後面會有附上相關連結,有興趣的讀者可以自己去研究一下
由於 JS 本身是 單線程序(single-threaded),代表一次只能有一件事能被執行,所以當出現一個很大的計算的時候,就會導致後面的計算沒辦法被執行。並且如果計算時間多過於 16.6 ms 的話,畫面就會出現卡頓,所以我們將這些計算移到背景去執行,這個機制就叫 Event Loop
當今天瀏覽器在運行 javaScript 程式碼時,會產生一個東西叫做 Execution Context(執行上下文),並會分成兩個部分: creation phase, execution phase
creation phase 會產生四個步驟:
execution phase 會有以下步驟:
這邊因為要討論的部分不是 Execution Context,所以這邊就不做太多的著墨,有興趣的讀者可以參考這篇文章
現在要來講一下今天的主題: Macrotask vs Microtask,這兩個行為會是發生在 execution phase
期間
我們都知道當 javaScript 執行到需要非同步的程式碼時,會把這個需要非同步的程式碼先放到 task queue
中,並且繼續執行其他程式碼,待其他程式碼都執行完成後,才會回到 task queue
中,將 task queue
中的 function 丟回到 call stack
上來執行
如果想看動畫版的執行順序,可以參考這個 Project
但即使都是非同步的程式碼,卻還是有執行的先後順序,主要分成兩個部分:
Macrotask: Web API (setTimeout, setInterval, ….)
Microtask: Promise
在了解先後順序前,我想先請各位讀者試著先研究一下下方程式碼會 alert 出什麼結果
setTimeout(() => alert("setTimeout"));
Promise.resolve()
.then(() => alert("Promise"));
alert("global");
答案是: global => Promise => setTimeout
你是否答對了呢?
恭喜,所以我們現在可以知道執行順序是: Microtask => Macrotask
但是,其實執行順序是: Macrotask => Microtask,等等,那為什麼印出來的結果是: global => Promise => setTimeout
,而不是: global => setTimeout => Promise
?
原因是這樣的,當頁頁面開啟時,載入對應的 JS 檔並且執行這件事情,就是一個 Macrotask
所以當 第一個 Macrotask 執行完成後,會去把所有的 Microtask 執行完,才會去執行第二個 Macrotask
Immediately after every macrotask, the engine executes all tasks from microtask queue, prior to running any other macrotasks or rendering or anything else.
以下放上示意圖
Macrotask -> All Microtask -> Macrotask
按照上面的示意圖,我們回到程式碼,就會長這樣:
Macrotask(載入對應的 JS 檔) -> All Microtask (Promise) -> Macrotask (setTimeout)
這邊幫各位整合幾個結論:
以上就是今天的文章,希望有幫助到大家,那我們下次見,拜拜
(有任何問題或是想討論的地方,都歡迎留言、或是私訊我,謝謝)
有興趣的朋友可以追蹤我的 Medium
參考文章:
https://ithelp.ithome.com.tw/articles/10296041
https://ithelp.ithome.com.tw/articles/10222737
https://javascript.info/event-loop